package com.site.controller;

import com.site.common.Builder;
import com.site.common.R;
import com.site.common.annotation.EncryRSA;
import com.site.util.AESUtil;
import com.site.util.JacksonUtil;
import com.site.util.RSAUtil;
import com.site.common.EntryRequest;
import com.site.vo.RequestRSAVo;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;
import java.util.UUID;

/**
 * RSA+AES实现接口验签和参数加密
 */
@EncryRSA
@RestController
public class EntryRSATestController {

    /****先给调用方分配一组RSA密钥和一个appId****/
    //初始化RSA密钥
    public static Map<String, Object> init = RSAUtil.init();
    //私钥
    public static String privateKey = RSAUtil.getPrivateKey(init);
    //公钥
    public static String publicKey = RSAUtil.getPublicKey(init);
    //appId，32位的uuid
    public static String appId = getUUID32();
    /****先给调用方分配一组RSA密钥和一个appId****/


    private static String  getUUID32(){
        return UUID.randomUUID().toString().replace("-","");
    }

    /**
     * 测试表单接收参数
     * 请求参数：{"name": "小二","job": "程序猿","hobby": "打篮球"}
     * 表单方式与json注解方式都可
     * @param requestRSAVo
     * @return
     */
    @PostMapping("/test111")
    public R<RequestRSAVo> test(RequestRSAVo requestRSAVo){
        return R.ok(requestRSAVo);
    }

    /**
     * 使用自定义注解与过滤器方式统一解密参数
     * 注意：必须 json 方式接收参数
     * 请求参数：EncryRequest 实体类{ "serviceId": null,"requestId": "","appId": "","sign": "","aseKey": "","timestamp": 1629167101888,"body": ""}
     * @param requestRSAVo
     * @return
     */
    @EncryRSA(method = RequestMethod.POST)
    @RequestMapping("/decrypt2")
    public R<RequestRSAVo> decrypt2(@RequestBody RequestRSAVo requestRSAVo){
        return R.ok(requestRSAVo);
    }

    /**
     * 生成签名并返回结果（调用方（请求方））
     * @return
     * @throws Exception
     */
    @RequestMapping("/create")
    public R<EntryRequest> entry() throws Exception {
        /****先给调用方分配一组RSA密钥和一个appId****/
        //初始化RSA密钥
        /*Map<String, Object> init = RSAUtil.init();
        //私钥
        String privateKey = RSAUtil.getPrivateKey(init);
        //公钥
        String publicKey = RSAUtil.getPublicKey(init);
        //appId，32位的uuid
        String appId = getUUID32();*/
        /****先给调用方分配一组RSA密钥和一个appId****/

        // 1.业务参数
//        Map<String,Object>  businessParams = new HashMap<>();
//        businessParams.put("name","小二");
//        businessParams.put("job","程序猿");
//        businessParams.put("hobby","打篮球");
        RequestRSAVo businessParams = Builder.of(RequestRSAVo::new)
                .with(RequestRSAVo::setName,"小二")
                .with(RequestRSAVo::setJob,"程序猿")
                .with(RequestRSAVo::setHobby,"打篮球")
                .build();

        //使用appId的前16位作为AES密钥，并对密钥进行rsa公钥加密
        String aseKey = appId.substring(0, 16);
        EntryRequest entryRequest = Builder.of(EntryRequest::new)
                .with(EntryRequest::setAppId, appId)
                .with(EntryRequest::setRequestId, getUUID32())
                .with(EntryRequest::setAseKey,new String(RSAUtil.encryptByPublicKey(aseKey,publicKey)))
                .with(EntryRequest::setBody,AESUtil.encrypt(JacksonUtil.beanToJsonString(businessParams),aseKey,appId.substring(16)))
                .with(EntryRequest::setTimestamp,System.currentTimeMillis())
                .build();
        Map<String, Object> paramMap = RSAUtil.bean2Map(entryRequest);// jsonRequest 转 map
        paramMap.remove("sign");
        // 参数排序
        Map<String, Object> sortedMap = RSAUtil.sort(paramMap);
        // 拼接参数：key1Value1key2Value2
        String urlParams = RSAUtil.groupStringParam(sortedMap);
        // （私钥）生成签名
        entryRequest.setSign(RSAUtil.sign(urlParams.getBytes(),privateKey));
        return R.ok(entryRequest);
    }

    /**
     * 解密（接收方（自己的系统））
     * @param entryRequest
     * @return
     */
    @RequestMapping("/decrypt")
    public R<EntryRequest> decrypt(@RequestBody EntryRequest entryRequest){
        // 使用appId的前16位作为AES密钥，并对密钥进行rsa公钥加密
        // 1.验签
        Map<String, Object> paramMap = RSAUtil.bean2Map(entryRequest);
        paramMap.remove("sign");
        // 参数排序
        Map<String, Object> sortedMap = RSAUtil.sort(paramMap);
        // 拼接参数：key1Value1key2Value2
        String urlParams = RSAUtil.groupStringParam(sortedMap);
        // 签名验证（公钥验证签名，私钥生成签名）
        boolean verify = RSAUtil.verify(urlParams.getBytes(), publicKey, entryRequest.getSign());
        if (!verify){
            return R.error("签名验证失败");
        }
        // 2.私钥解密，获取aseKey
        String aseKey = RSAUtil.decryptByPrivateKey(entryRequest.getAseKey().getBytes(), privateKey);
        // 解密请求报文
        String requestBody = "";
        try {
            requestBody = AESUtil.decrypt(entryRequest.getBody(), aseKey, appId.substring(16));
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("请求参数解密异常");
        }
        entryRequest.setBody(requestBody);
        return R.ok(entryRequest);
    }
}